Service COM during frame throttle so screen readers stay responsive#4761
Service COM during frame throttle so screen readers stay responsive#4761RealAmethyst wants to merge 1 commit into
Conversation
| private static extern IntPtr CreateEventW(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, IntPtr lpName); | ||
|
|
||
| private const uint COWAIT_DISPATCH_CALLS = 0x8; | ||
| private static readonly IntPtr[] _responsiveSleepHandles = { CreateEventW(IntPtr.Zero, true, false, IntPtr.Zero) }; |
There was a problem hiding this comment.
I suspect this will need OSTailoredCode.IsUnixHost ? [ default ] : to avoid crashing on startup.
| /// </summary> | ||
| private static void ResponsiveSleep(int ms) | ||
| { | ||
| if (ms < 1) ms = 1; |
There was a problem hiding this comment.
Both callers already pass in >= 1, so this line can be removed.
|
I don't know how a screenreader is typically used, but I started NVDA to see if I can notice anything, and I don't see what you mean when you say "laggy". If anything, there should be a <15ms delay in response time which should be negligible. |
|
so without this fix it's like 10 seconds of lag if not more, this fixes that, this also happens on every other screen reader I tested. If you don't get that lag can you please inform me of what screen reader version you use? |
|
I would be wary of trying to "pump COM messages" while sleeping. While technically the STA thread contract dictates this should be done, in practice this ends up causing more issues. This "fix" would also be incomplete, as this throttling is only applicable assuming Clock Throttle. Audio Throttle has sleep calls elsewhere and VSync Throttle / VSync Enabled are just impossible to "fix" here. I would also be skeptical about "very laggy" claims, the sleep calls are normally very short and message pumping occurs between them. Are you sure you didn't end up setting BizHawk to say 1% speed? (which case there will be big sleep calls, although in this case the UI would also just be laggy in the first place / this is a known issue) Also, |
|
Whenever I would open the emulator and try to use the UI it would be very lagy, this is also not just me, but every other blind user I've talked to has the exact same issue, this is before doing anything, not even loading a rom, as the UI is just slow with screenr eaders in general. It also does not matter what screen reader you use, same issue. |
|
Clearly there are more differences between Morilli's and my dev environments and a "real" user's environment, and it just hasn't occurred to any of us what those differences are. Do you use your PC with the screen off? Is the lag dependent on the display method (D3D vs GDI+)? Does Windows itself change if it's installed with a11y features enabled? |
|
I tried checking D3D vs GDI and no difference on my end, I have a monitor connected but it's not on most of the time, installing windows with accessibility stuff shouldn't change anything as it comes with the OS by default |
|
Just chiming in here as a fellow blind user to confirm that the lag is not imaginary :) IT's specifically just ambient as soon as you open the app with NVDA running. The slightly confusing thing is that the lag only occurs in screen reader response time, not in the app performance itself as far as I am aware. |
|
To be clear, does this lag also occur for Audio Throttle and/or VSync Throttle and/or Vsync Enabled? |
|
I have no idea, as trying to turn those settings on is a pain due to screen reader lag, this happens without us changing any settings, just an program launch |
|
Tested more, the app itself is fast, no lag, games themselves has no lag, the screen reader itself lags, even when I try to do screen reader specific commands, when the emulator is in forground, it will lag, this is for all screen readers. |
EmuHawk's frame throttle uses Thread.Sleep, which does not dispatch incoming COM calls. Screen readers
(NVDA, Narrator, etc.) read the window via UI Automation / MSAA — COM calls marshaled to the STA UI
thread — so during every frame's sleep the thread stops answering them. The result: all screen readers
become very laggy whenever EmuHawk is the foreground window, even though the app itself stays responsive.
This replaces the two Thread.Sleep calls in Throttle.cs with a small ResponsiveSleep that waits the same
duration via CoWaitForMultipleHandles(COWAIT_DISPATCH_CALLS, ...), which dispatches COM calls during the
wait (COM only — no window input/paint — so there's no reentrancy into the emulation loop). The Unix
path keeps Thread.Sleep, since CoWaitForMultipleHandles is Windows-only.